package com.yc.jpa;

import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Propagation;

import com.yc.entity.Clazz;
import com.yc.entity.Grade;
import com.yc.entity.Student;
import com.yc.entity.Teacher;
import com.yc.entity.TestIdGenerator;
import com.yc.entity.TestUUID;
import com.yc.entity.TestUUID2;
import com.yc.entity.TestUUIDhex;
import com.yc.jpa.dao.GradeDao;
import com.yc.jpa.dao.StudentDao;

public class JpaTest {
	private EntityManagerFactory entityManagerFactory;
	private EntityManager entityManager;
	private EntityTransaction transaction;

	@Before
	public void init() {
		/**
		 * 通过Persistence获取EntityManagerFactory， 传入参数对应配置文件中持久化单元persistence-unit的name
		 * 通过EntityManagerFactory创建EntityManager 获取EntityTransaction 开启事务
		 */
		entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
		entityManager = entityManagerFactory.createEntityManager();
		transaction = entityManager.getTransaction();
		transaction.begin();
	}

	@After
	public void distory() {
		/**
		 * 提交事务 关闭entityManager 关闭entityManagerFactory
		 */
		transaction.commit();
		entityManager.close();
		entityManagerFactory.close();
	}
	
	/**
	 * 如果 A 是一个 detached( 分离 ) 状态的实体，该方法会抛出 IllegalArgumentException 异常，具体异常根据不同的 JPA 实现有关。
	 * 这里报：org.hibernate.PersistentObjectException: detached entity passed to persist: com.yc.entity.Grade
	 */
//	@Test
//	public void testPersist() {
//		Grade grade = new Grade();
//		grade.setName("十一年级");
//		grade.setNumber(3);
//        entityManager.persist(grade);//转换为托管状态
//		
//        entityManager.flush();//转换为持久化态
//        
//        entityManager.clear();//变成游离态
//		
//		grade.setName("十一年级-1");
//		entityManager.persist(grade);
//		
//	}
	
//	/**
//	 *  如果 A 是一个 removed( 删除 ) 状态的实体，它将会转换为受控状态
//	 *  这里就是“没删除掉”
//	 */
//	@Test
//	public void testPersist2() {
//		
//		Grade g = entityManager.find(Grade.class, 5);
//		entityManager.remove(g);//变为删除状态
//		
//		entityManager.persist(g);
//		
//	}
	
	/**
	 * 如果 A 是一个 detached 状态的实体，该方法会将 A 的修改提交到数据库，并返回一个新的 managed 状态的实例 A2
	 * 试验结果：正常变为托管状态，实体类一旦改变 就会同步到数据库； 但如果托管状态执行了entityManager.detach,那么就成为游离态的，
	 * 游离态的实体类不会主动判断内存内容和数据库是否一样。  这里和网上说的不一致：merge并不会把游离态 转换为托管状态。
	 * 而是在调用merge时 同步内存数据和数据库数据，如果不一致，则把内存数据同步到数据库，也就是此后即时再改变实体类数据，也不会自动
	 * 同步到数据库库。 
	 * 也就是说：merge有能力把new的实体类转换为托管态，却没有能力把游离态的转换为托管态。 
	 * 托管态的实体类一旦被detach转换为游离态，就回不到正常的托管状态了，即时是persist也不行（此时再用persist反而会出现奇怪的结果）
	 */
//	@Test
//	public void testMerge() {
//		
//		Grade grade = new Grade();
//		grade.setName("十二年级");
//		grade.setNumber(12);
//        entityManager.persist(grade);//转换为托管状态
//        entityManager.clear();//变成游离态
////        entityManager.detach(grade);
//        
////        Grade greade_ret = entityManager.merge(grade);
//        
////        entityManager.persist(grade);
//        grade.setName("十二年级-----");
////        entityManager.refresh(grade);
////		Grade grade = entityManager.find(Grade.class, 5);
//        
//	}
	
	/**
	 * 如果 A 是一个 removed 状态的实体，该方法会抛出 IllegalArgumentException 异常
	 * 这里报：Transaction was marked for rollback only; cannot commit
	 * 无论哪个报错 都没有明确的告知是什么问题，也就是说这样的错误写法需要记下，因为出现bug后靠日志不太好知道错误原因
	 */
//	@Test
//	public void testMerge2() {
//		
//		Grade grade = entityManager.find(Grade.class, 5);//托管状态
//		
////		entityManager.remove(grade);//删除状态
//		
////		entityManager.persist(grade);//再次回到托管状态，前面的删除操作失效
////		grade.setName("五年级");
////		entityManager.merge(grade);//
//		
//		transaction.rollback();
//		transaction.begin();
//		grade.setName("五年级-new");
//		
//	}
	
	/**
	 * 注意点：只有托管态的才能通过remove删除
	 */
//	@Test
//	public void testRemove() {
//		Grade grade = new Grade();
//		grade.setId(8);
//		grade.setName("七年级");
//		entityManager.remove(grade);
//	}
	

//	@Test
//	public void testInsert() {
//		Clazz clz1 = new Clazz();
//        clz1.setName("计科1601");
//        clz1.setDate(new Date());
//        //clz1.setId(6);
//        
//        Student stu1 = new Student();
//        stu1.setName("mary");
//        stu1.setTel("18866005544");
//        stu1.setDate(new Date());
//        stu1.setClazz(clz1);
//        
//        entityManager.persist(clz1);
//        entityManager.persist(stu1);
//	}
	
	/**
	 * 如果 A 是一个 new 状态的实体，它将会转为 managed 状态
	 */
//	@Transactional(notRollbackFor=RunTimeException.class)
//	@org.springframework.transaction.annotation.Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
//	@Test
//	public void testInsert2() {
//		
//		Grade grade = new Grade();
//		grade.setName("十六年级");
//		grade.setNumber(3);
//        entityManager.persist(grade);//转换为托管状态
////		grade = entityManager.merge(grade);
////        grade.setName("十六年级--");
//        
//        System.out.println(grade.getId());
//        
//	}
	
	
	  /**
	   * 被删除的对象也必须是被jpa管理的持久化对象
	   */
//	  @Test
//	  public void testDeleteStu() {
//	      Student stu = entityManager.find(Student.class, 1);
//	      entityManager.remove(stu);
//	  }
	
//	  @Test
//	  public void testDeleteClz() {
//		  Clazz cla = entityManager.find(Clazz.class, 2);
//	      entityManager.remove(cla);
//	  }
	
//	  @Test
//	  public void testDeleteClz() {
//	      Clazz clz = entityManager.find(Clazz.class, 4);
//	      Set<Student> stus = clz.getStus();
//	      stus.forEach((stu) -> stu.setClazz(null));//更新之后直接修改数据库
//	      entityManager.remove(clz);
//	  }
	
//	  @Test
//	  public void testM() {
//	      Clazz clz = entityManager.find(Clazz.class, 5);
//	      
//	      Student student = new Student();
//	      student.setId(5);
//	      student.setName("lee");
//	      student.setDate(new Date());
//	      student.setTel("1885656565");
//	      student.setClazz(clz);
//	      
//	      Student stu = entityManager.merge(student);//有id，更新
//	  }
	
	/**
	 * 根据持久化对象性质，直接修改。修改后jpa会在事务提交时自动检查缓存中的内容是否和数据库中一致，不一致就会更新
	 */
//	  @Test
//	  public void testChange() {
//	      Clazz clz = entityManager.find(Clazz.class, 5);//托管状态，只要改变就会在事务提交的时候，同步到数据库
//	      Student student = entityManager.find(Student.class, 4);//托管状态，只要改变就会在事务提交的时候，同步到数据库
//	      student.setClazz(clz);
//	      
//	      Grade gra = entityManager.find(Grade.class, 5);//托管状态，只要改变就会在事务提交的时候，同步到数据库
//	      gra.setName("五年级");
//	      
//	  }
	
	  
	/**
	 * find方法查询
	 */
//	  @Test
//	  public void testQuery() {
//	      Clazz clazz = entityManager.find(Clazz.class, 5);
//	      Set<Student> stus = clazz.getStus();
//	      for (Student st : stus) {
//			System.out.println(st.getName());
//		}
//	  }
	  
	/**
	 * JPQL语句查询
	 */
//	  @Test
//	  public void testJpql() {
//	      String sql = "select c from Clazz c where c.name=?1";
//	      Query query = entityManager.createQuery(sql);
//	      query.setParameter(1, "test");
//	      List res = query.getResultList();
//	      System.out.println("条数：" + res.size());
//	  }
	  
//	@Test
//	public void testDQuery() {
//		// 用来构建查询条件
//		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
//		// 合成最终的查询语句
//		CriteriaQuery<Clazz> query = cb.createQuery(Clazz.class);
//		// 通过Root可以获取当前被查询的实体类中的属性，在和CriteriaBuilder创建查询条件
//		Root<Clazz> root = query.from(Clazz.class);
//		// 通过CriteriaBuilder构建的一个等于的查询条件
//		Predicate predicate = cb.equal(root.get("id"), 5);
//		// where接收的是一个可变参数，合成所有的查询条件
//		query.where(predicate);
//		// 传入CriteriaQuery，查询结果
//		Clazz clz = entityManager.createQuery(query).getSingleResult();
//
//		System.out.println(clz.getName());
//	}
	
	
	/**
	 * 通过调用 JPA 命名查询语句创建查询:在实体类上定义查询语句
	 */
//	@Test
//	public void testDQuery2() {
//		
//		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-servlet.xml"); 
//		StudentDao studentDao = ctx.getBean(StudentDao.class);
//		
//		List<Student> list1 = studentDao.findMyTel("1885656565");
//		System.out.println(list1.get(0).getName());
//		System.out.println("---------------------");
//		List<String> list2 = studentDao.findAllTel();
//		for (String tel : list2) {
//			System.out.println(tel);
//		}
//	}

	
	
//	@Test
//	public void test() {
//		
//		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 
//		GradeDao gradeDao = ctx.getBean(GradeDao.class);
//		
//		gradeDao.test();
//	}
	
//	@Test
//	public void testLazyLoad() {
//		Student stu = entityManager.find(Student.class, 5);
//		System.out.println("name: " + stu.getName());
//		System.out.println(stu.getClazz().getName());
//	}
	
//	@Test
//	public void testLazyLoad2() {
//		Clazz cla = entityManager.find(Clazz.class, 5);
//		System.out.println("name: " + cla.getName());
//		Set<Student> set = cla.getStus();
//		Student st = set.iterator().next();
//		System.out.println("---------" + st.getName());
//	}
	
//	@Test
//	public void testLazyLoad3() {
//		Teacher tea = entityManager.find(Teacher.class, 5);
//		System.out.println("name: " + tea.getName());
//	}
//	
//	@Test
//	public void testJpql() {
//		String jpql = "select d from Student d";
//		Query query = entityManager.createQuery(jpql);
//		List list = query.getResultList();//返回结果列表
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	@Test
//	public void testMerge() {
//		Student stu = new Student();
//		stu.setName("aaa");
//		stu.setId(17);
//		entityManager.merge(stu);
//	}
//	
//	@Test
//	public void testPersist3() {
//		Student stu = entityManager.find(Student.class, 17);
//		entityManager.detach(stu);
//		
//		entityManager.persist(stu);
//	}
	
//	@Test
//	public void testNativeQuery() {
//		String jqpl = "select * from t_student";
//		Query query = entityManager.createNativeQuery(jqpl);
//		List<Object[]> list = query.getResultList();//返回值是一个数组集合
//		for (Object[] arr : list) {
//			System.out.println(arr[0] + ", " + arr[1] + ", " + arr[2] + ", " + arr[3]);
//		}
//		
//	}
	
//	@Test
//	public void testUUID() {
////		Student stu = new Student();
////		stu.setName("ssss");
////		entityManager.persist(stu);
//		
//		TestUUID td = new TestUUID();
//		td.setName("aaaaaa");
//		entityManager.persist(td);
//	}
	
//	@Test
//	public void testMoreUUID() {
//		TestUUID td = null;
//		for (int i = 0; i < 100; i++) {
//			td = new TestUUID();
//			td.setName(""+i);
//			entityManager.persist(td);
//		}
//	}
	
//	@Test
//	public void testMoreIdGenerator() {
//		TestIdGenerator td = null;
//		for (int i = 0; i < 100; i++) {
//			td = new TestIdGenerator();
//			td.setName(""+i);
//			entityManager.persist(td);
//		}
//	}
	
//	@Test
//	public void testMoreUUID2() {
//		TestUUID2 td = null;
//		for (int i = 0; i < 100; i++) {
//			td = new TestUUID2();
//			td.setName(""+i);
//			entityManager.persist(td);
//		}
//	}
	
	@Test
	public void testMoreUUIDhex() {
		TestUUIDhex td = null;
		for (int i = 0; i < 100; i++) {
			td = new TestUUIDhex();
			td.setName(""+i);
			entityManager.persist(td);
		}
	}
	
	
}
